/**
 * 
 */
package qy.jalgotrade.technical;

import com.google.common.math.DoubleMath;

import it.unimi.dsi.fastutil.doubles.DoubleList;
import qy.jalgotrade.dataseries.SequenceDataSeries;
import qy.jalgotrade.utils.CommonUtils;

/**
 * @author qy
 *
 */
public class RateOfChange extends EventBasedFilter<Double> {

	private class ROCEventWindow extends EventWindow<Double> {

		/**
		 * 
		 * @param windowSize
		 */
		public ROCEventWindow(int windowSize) {

			super(windowSize, Double.class);
		}

		/*
		 * 
		 */
		@Override
		public Double getValue() {

			double ret = Double.NaN;
			if (windowFull()) {
				DoubleList values = (DoubleList) getValues();
				if (values.size() > 0) {
					double prev = values.getDouble(0);
					double actual = values.getDouble(values.size() - 1);
					if (!Double.isNaN(actual) && !Double.isNaN(prev)) {
						double diff = actual - prev;
						if (DoubleMath.fuzzyEquals(diff, 0, CommonUtils.FUZZY_EQUAL_TOLERANCE_MATH)) {
							ret = 0;
						} else if (!DoubleMath.fuzzyEquals(prev, 0, CommonUtils.FUZZY_EQUAL_TOLERANCE_MATH)) {
							ret = diff / prev;
						}
					}
				}
			}
			return ret;
		}
	}

	/**
	 * 
	 * @param dataSeries
	 * @param valuesAgo
	 * @throws Exception
	 */
	public RateOfChange(SequenceDataSeries<Double> dataSeries, int valuesAgo) throws Exception {

		this(dataSeries, valuesAgo, 0);
	}

	/**
	 * 
	 * @param dataSeries
	 * @param valuesAgo
	 * @param maxLen
	 * @throws Exception
	 */
	public RateOfChange(SequenceDataSeries<Double> dataSeries, int valuesAgo, int maxLen) throws Exception {

		super(maxLen);
		ROCEventWindow win = new ROCEventWindow(valuesAgo + 1);
		_init(dataSeries, win);
	}
}
